module cpu_axi_interface
(
    input         clk,          // 时钟信号
    input         resetn,       // 复位信号（低电平有效）

    //inst sram-like            // CPU 指令接口（类 SRAM 接口）
    input         inst_req,     // 指令请求信号
    input         inst_wr,      // 指令写使能
    input  [1 :0] inst_size,    // 指令大小（00:byte, 01:half word, 10:word）
    input  [31:0] inst_addr,    // 指令地址
    input  [31:0] inst_wdata,   // 指令写数据
    output [31:0] inst_rdata,   // 指令读数据
    output        inst_addr_ok, // 指令地址握手成功
    output        inst_data_ok, // 指令数据握手成功
    
    //data sram-like           // CPU 数据接口（类 SRAM 接口）
    input         data_req,     // 数据请求信号
    input         data_wr,      // 数据写使能
    input  [1 :0] data_size,    // 数据大小（00:byte, 01:half word, 10:word）
    input  [31:0] data_addr,    // 数据地址
    input  [31:0] data_wdata,   // 数据写数据
    output [31:0] data_rdata,   // 数据读数据
    output        data_addr_ok, // 数据地址握手成功
    output        data_data_ok, // 数据传输完成

    //axi 总线接口信号
    //ar (读地址通道)
    output [3 :0] arid,         // 读地址 ID
    output [31:0] araddr,       // 读地址
    output [7 :0] arlen,        // 突发传输长度
    output [2 :0] arsize,       // 传输大小
    output [1 :0] arburst,      // 突发类型
    output [1 :0] arlock,       // 锁定类型
    output [3 :0] arcache,      // Cache 类型
    output [2 :0] arprot,       // 保护类型
    output        arvalid,      // 读地址有效
    input         arready,      // 从机准备好接收读地址

    //r (读数据通道)           
    input  [3 :0] rid,          // 读 ID tag
    input  [31:0] rdata,        // 读数据
    input  [1 :0] rresp,        // 读响应
    input         rlast,        // 读最后一个
    input         rvalid,       // 读数据有效
    output        rready,       // 主机准备好接收读数据

    //aw (写地址通道)          
    output [3 :0] awid,         // 写地址 ID
    output [31:0] awaddr,       // 写地址
    output [7 :0] awlen,        // 突发传输长度
    output [2 :0] awsize,       // 传输大小
    output [1 :0] awburst,      // 突发类型
    output [1 :0] awlock,       // 锁定类型
    output [3 :0] awcache,      // Cache 类型
    output [2 :0] awprot,       // 保护类型
    output        awvalid,      // 写地址有效
    input         awready,      // 从机准备好接收写地址

    //w (写数据通道)          
    output [3 :0] wid,          // 写 ID tag
    output [31:0] wdata,        // 写数据
    output [3 :0] wstrb,        // 写数据选通
    output        wlast,        // 写最后一个
    output        wvalid,       // 写数据有效
    input         wready,       // 从机准备好接收写数据

    //b (写响应通道)           
    input  [3 :0] bid,          // 写响应 ID
    input  [1 :0] bresp,        // 写响应
    input         bvalid,       // 写响应有效
    output        bready        // 主机准备好接收写响应
);

// 请求状态寄存器
reg do_req;                     // 是否有正在处理的请求
reg do_req_or;                  // 请求类型（1:数据请求，0:指令请求）
reg        do_wr_r;            // 写请求标志
reg [1 :0] do_size_r;          // 访问大小
reg [31:0] do_addr_r;          // 请求地址
reg [31:0] do_wdata_r;         // 写数据
wire data_back;                // 数据返回标志

// SRAM 接口控制逻辑
assign inst_addr_ok = !do_req&&!data_req;    // 指令地址握手条件
assign data_addr_ok = !do_req;               // 数据地址握手条件

// 请求状态更新逻辑
always @(posedge clk)
begin
    // 请求状态寄存器更新
    do_req     <= !resetn                       ? 1'b0 : 
                  (inst_req||data_req)&&!do_req ? 1'b1 :
                  data_back                     ? 1'b0 : do_req;
    
    // 请求类型寄存器更新
    do_req_or  <= !resetn ? 1'b0 : 
                  !do_req ? data_req : do_req_or;

    // 保存请求的具体信息
    do_wr_r    <= data_req&&data_addr_ok ? data_wr :
                  inst_req&&inst_addr_ok ? inst_wr : do_wr_r;
    do_size_r  <= data_req&&data_addr_ok ? data_size :
                  inst_req&&inst_addr_ok ? inst_size : do_size_r;
    do_addr_r  <= data_req&&data_addr_ok ? data_addr :
                  inst_req&&inst_addr_ok ? inst_addr : do_addr_r;
    do_wdata_r <= data_req&&data_addr_ok ? data_wdata :
                  inst_req&&inst_addr_ok ? inst_wdata :do_wdata_r;
end

// SRAM 接口响应信号生成
assign inst_data_ok = do_req&&!do_req_or&&data_back;  // 指令数据完成
assign data_data_ok = do_req&& do_req_or&&data_back;  // 数据传输完成
assign inst_rdata   = rdata;                          // 指令读数据
assign data_rdata   = rdata;                          // 数据读数据

// AXI 传输状态控制
reg addr_rcv;    // 地址已接收标志
reg wdata_rcv;   // 写数据已接收标志

// 数据返回条件：地址已接收，且读数据有效或写响应有效
assign data_back = addr_rcv && (rvalid&&rready||bvalid&&bready);

// AXI 传输状态更新
always @(posedge clk)
begin
    addr_rcv  <= !resetn          ? 1'b0 :
                 arvalid&&arready ? 1'b1 :
                 awvalid&&awready ? 1'b1 :
                 data_back        ? 1'b0 : addr_rcv;
    wdata_rcv <= !resetn        ? 1'b0 :
                 wvalid&&wready ? 1'b1 :
                 data_back      ? 1'b0 : wdata_rcv;
end

// AXI 读地址通道信号赋值
assign arid    = 4'd0;                     // 读 ID 固定为 0
assign araddr  = do_addr_r;                // 读地址
assign arlen   = 8'd0;                     // 突发长度为 1
assign arsize  = do_size_r;                // 读大小
assign arburst = 2'd0;                     // FIXED 突发类型
assign arlock  = 2'd0;                     // 普通访问
assign arcache = 4'd0;                     // 非缓存访问
assign arprot  = 3'd0;                     // 特权级访问
assign arvalid = do_req&&!do_wr_r&&!addr_rcv;  // 读请求且地址未被接收

// AXI 读数据通道
assign rready  = 1'b1;                     // 永远准备接收读数据

// AXI 写地址通道信号赋值
assign awid    = 4'd0;                     // 写 ID 固定为 0
assign awaddr  = do_addr_r;                // 写地址
assign awlen   = 8'd0;                     // 突发长度为 1
assign awsize  = do_size_r;                // 写大小
assign awburst = 2'd0;                     // FIXED 突发类型
assign awlock  = 2'd0;                     // 普通访问
assign awcache = 4'd0;                     // 非缓存访问
assign awprot  = 3'd0;                     // 特权级访问
assign awvalid = do_req&&do_wr_r&&!addr_rcv;   // 写请求且地址未被接收

// AXI 写数据通道信号赋值
assign wid    = 4'd0;                      // 写 ID 固定为 0
assign wdata  = do_wdata_r;                // 写数据
// 根据大小生成写选通信号
assign wstrb  = do_size_r==2'd0 ? 4'b0001<< do_addr_r[1:0] :  // 字节写
                do_size_r==2'd1 ? 4'b0011<< do_addr_r[1:0] :  // 半字写
                4'b1111;                                       // 全字写
assign wlast  = 1'd1;                      // 永远是最后一个数据
assign wvalid = do_req&&do_wr_r&&!wdata_rcv;   // 写请求且数据未被接收

// AXI 写响应通道
assign bready  = 1'b1;                     // 永远准备接收写响应

endmodule